package com.buer.train.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.buer.train.business.dto.DocDTO;
import com.buer.train.business.service.EsService;
import com.buer.train.common.constant.Constant;
import com.buer.train.common.eumn.ResultEnum;
import com.buer.train.common.handle.BaseException;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Service
public class EsServiceImpl implements EsService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public int add(DocDTO docDTO) {
        //1.	构建IndexRequest对象，用来描述ES发起请求的数据。
        IndexRequest indexRequest = new IndexRequest(Constant.DOC_INDEX);

        //2.	设置文档ID。
        indexRequest.id(docDTO.getId() + "");

        //3.	使用FastJSON将实体类对象转换为JSON。
        String json = JSONObject.toJSONString(docDTO);

        //4.	使用IndexRequest.source方法设置文档数据，并设置请求的数据为JSON格式。
        indexRequest.source(json, XContentType.JSON);

        //5.	使用ES High level client调用index方法发起请求，将一个文档添加到索引中。
        try {
            IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            return index.status().getStatus()==201?1:0;
        } catch (IOException e) {
            throw new BaseException(ResultEnum.ES_SERVER_ERROR);
        }
    }

    @Override
    public int update(DocDTO docDTO) {
        // 1.	判断对应ID的文档是否存在
        // a)	构建GetRequest
        try {

            GetRequest getRequest = new GetRequest(Constant.DOC_INDEX, docDTO.getId() + "");

            // b)	执行client的exists方法，发起请求，判断是否存在
            boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);

            if (exists) {
                // 2.	构建UpdateRequest请求
                UpdateRequest updateRequest = new UpdateRequest(Constant.DOC_INDEX, docDTO.getId() + "");

                // 3.	设置UpdateRequest的文档，并配置为JSON格式
                updateRequest.doc(JSONObject.toJSONString(docDTO), XContentType.JSON);

                // 4.	执行client发起update请求
                UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
                return update.status().getStatus()==200?1:0;
            }
            return 0;
        } catch (IOException e) {
            throw new BaseException(ResultEnum.ES_SERVER_ERROR);
        }
    }

    @Override
    public int delete(Integer id) {

        // 1.	构建delete请求
        DeleteRequest deleteRequest = new DeleteRequest(Constant.DOC_INDEX, id + "");

        // 2.	使用RestHighLevelClient执行delete请求
        try {
            DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            return delete.status().getStatus()==200?1:0;
        } catch (IOException e) {
            throw new BaseException(ResultEnum.ES_SERVER_ERROR);
        }

    }

    @Override
    public Map<String, Object> searchByPage(String keywords, int pageNum, int pageSize) {
        // 1.构建SearchRequest检索请求
        // 专门用来进行全文检索、关键字检索的API
        SearchRequest searchRequest = new SearchRequest(Constant.DOC_INDEX);

        // 2.创建一个SearchSourceBuilder专门用于构建查询条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // 3.使用QueryBuilders.multiMatchQuery构建一个查询条件（搜索title、jd），并配置到SearchSourceBuilder
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keywords, "author","title","content");

        // 将查询条件设置到查询请求构建器中
        searchSourceBuilder.query(multiMatchQueryBuilder);

        // 每页显示多少条
        searchSourceBuilder.size(pageSize);
        // 设置从第几条开始查询
        searchSourceBuilder.from((pageNum - 1) * pageSize);

        // 4.调用SearchRequest.source将查询条件设置到检索请求
        searchRequest.source(searchSourceBuilder);

        // 5.执行RestHighLevelClient.search发起请求
        SearchResponse searchResponse=null;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        }catch (Exception e){
            throw new BaseException(ResultEnum.ES_SERVER_ERROR);
        }

        SearchHit[] hitArray = searchResponse.getHits().getHits();

        // 6.遍历结果
        ArrayList<DocDTO> docDTOArrayList = new ArrayList<>();

        for (SearchHit documentFields : hitArray) {
            // 1)获取命中的结果
            String json = documentFields.getSourceAsString();

            // 2)将JSON字符串转换为对象
            DocDTO docDTO = JSONObject.parseObject(json, DocDTO.class);

            // 3)使用SearchHit.getId设置文档ID
            docDTO.setId(Integer.valueOf(documentFields.getId()));

            docDTOArrayList.add(docDTO);
        }

        // 8.	将结果封装到Map结构中（带有分页信息）
        // a)	total -> 使用SearchHits.getTotalHits().value获取到所有的记录数
        // b)	content -> 当前分页中的数据
        long totalNum = searchResponse.getHits().getTotalHits().value;
        HashMap hashMap = new HashMap();
        hashMap.put("total", totalNum);
        hashMap.put("list", docDTOArrayList);


        return hashMap;
    }
}
